package com.evil.common.core.util;

import cn.hutool.core.collection.CollectionUtil;
import com.evil.common.core.exception.BusinessException;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * lambdas8 Stream
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
public class StreamUtil {

    /**
     * 获取第一个元素
     *
     * @param list   list
     * @param filter filter
     * @param def    def
     * @param <T>    T
     * @return T
     */
    public static <T> T getFirst(Collection<T> list, Predicate<T> filter, T def) {
        return list.stream().filter(filter).findFirst().orElse(def);
    }

    /**
     * 获取第一个元素
     *
     * @param list list
     * @param <T>  T
     * @return T
     */
    public static <T> T findFirst(Collection<T> list) {
        return list.stream().findFirst().orElseThrow(BusinessException::new);
    }

    /**
     * 获取第一个元素
     *
     * @param list   list
     * @param filter filter
     * @param <T>    T
     * @return T
     */
    public static <T> T findFirst(Collection<T> list, Predicate<T> filter) {
        return list.stream().filter(filter).findFirst().orElseThrow(BusinessException::new);
    }

    /**
     * 获取第一个元素
     *
     * @param list              list
     * @param filter            filter
     * @param exceptionSupplier exceptionSupplier
     * @param <T>               T
     * @return T
     */
    public static <T, X extends Throwable> T findFirst(Collection<T> list, Predicate<T> filter, Supplier<? extends X> exceptionSupplier) throws Throwable {
        return list.stream().filter(filter).findFirst().orElseThrow(exceptionSupplier);
    }

    /**
     * 获取第一个元素
     *
     * @param list list
     * @param <T>  T
     * @return Optional
     */
    public static <T> Optional<T> isExistFirst(Collection<T> list) {
        return list.stream().findFirst();
    }

    /**
     * 获取第一个元素
     *
     * @param list   list
     * @param filter filter
     * @param <T>    T
     * @return Optional
     */
    public static <T> Optional<T> isExistFirst(Collection<T> list, Predicate<T> filter) {
        return list.stream().filter(filter).findFirst();
    }

    /**
     * 检阅list
     *
     * @param list list
     * @param peek peek
     * @param <T>  T
     * @return list
     */
    public static <T> List<T> peek(Collection<T> list, Consumer<T> peek) {
        return list.stream().peek(peek).collect(Collectors.toList());
    }

    /**
     * 检阅list
     *
     * @param list   list
     * @param filter filter
     * @param peek   peek
     * @param <T>    T
     * @return list
     */
    public static <T> List<T> peekF(Collection<T> list, Predicate<T> filter, Consumer<T> peek) {
        return list.stream().filter(filter).peek(peek).collect(Collectors.toList());
    }

    /**
     * 转换list
     *
     * @param list  list
     * @param trans trans
     * @param <T>   T
     * @param <V>   V
     * @return List
     */
    public static <T, V> List<V> transListT(Collection<T> list, Function<T, V> trans) {
        return list.stream().map(trans).collect(Collectors.toList());
    }

    /**
     * 转换list
     *
     * @param list   list
     * @param trans  trans
     * @param filter 过滤
     * @param <T>    T
     * @param <V>    V
     * @return List
     */
    public static <T, V> List<V> transListFT(Collection<T> list, Predicate<T> filter, Function<T, V> trans) {
        return list.stream().filter(filter).map(trans).collect(Collectors.toList());
    }

    /**
     * 转换list
     *
     * @param list   list
     * @param trans  trans
     * @param filter 过滤
     * @param <T>    T
     * @param <V>    V
     * @return List
     */
    public static <T, V> List<V> transListTF(Collection<T> list, Function<T, V> trans, Predicate<V> filter) {
        return list.stream().map(trans).filter(filter).collect(Collectors.toList());
    }

    /**
     * 转换set
     *
     * @param list  list
     * @param trans trans
     * @param <T>   T
     * @param <V>   V
     * @return List
     */
    public static <T, V> Set<V> transSetT(Collection<T> list, Function<T, V> trans) {
        return list.stream().map(trans).collect(Collectors.toSet());
    }

    /**
     * 转换set
     *
     * @param list  list
     * @param trans trans
     * @param <T>   T
     * @param <V>   V
     * @return List
     */
    public static <T, V> Set<V> transSetFT(Collection<T> list, Predicate<T> filter, Function<T, V> trans) {
        return list.stream().filter(filter).map(trans).collect(Collectors.toSet());
    }

    /**
     * 过滤
     *
     * @param list   list
     * @param filter filter
     * @param <T>    T
     * @return List
     */
    public static <T> List<T> filter(Collection<T> list, Predicate<T> filter) {
        return list.stream().filter(filter).collect(Collectors.toList());
    }

    /**
     * 过滤
     *
     * @param list   list
     * @param filter filter
     * @param <T>    T
     * @return List
     */
    public static <T> Set<T> filterSet(Collection<T> list, Predicate<T> filter) {
        return list.stream().filter(filter).collect(Collectors.toSet());
    }

    /**
     * 有序分组
     *
     * @param classifier Collectors.groupingBy#classifier
     * @param downstream Collectors.groupingBy#downstream
     * @param <T>        T
     * @param <K>        K
     * @param <A>        A
     * @param <D>        D
     * @return Collector
     */
    public static <T, K, A, D> Collector<T, ?, Map<K, D>> orderlyGroupBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) {
        return Collectors.groupingBy(classifier, LinkedHashMap::new, downstream);
    }

    /**
     * 有序组合
     *
     * @param keyMapper   Collectors.toMap#keyMapper
     * @param valueMapper Collectors.toMap#valueMapper
     * @param <T>         T
     * @param <K>         K
     * @param <U>         U
     * @return Collector
     */
    public static <T, K, U> Collector<T, ?, Map<K, U>> orderlyToMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) {
        return Collectors.toMap(keyMapper, valueMapper, (o, n) -> o, LinkedHashMap::new);
    }

    /**
     * 列表转Map
     *
     * @param list 列表
     * @param <T>  T
     * @return Map
     */
    public static <T> Map<T, T> toMap(Collection<T> list) {
        return list.stream().collect(Collectors.toMap(e -> e, e -> e));
    }

    /**
     * 列表转Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K> Map<K, T> toMapK(Collection<T> list, Function<T, K> getK) {
        return list.stream().collect(Collectors.toMap(getK, e -> e));
    }

    /**
     * 列表转Map
     *
     * @param list 列表
     * @param getV value方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K> Map<T, K> toMapV(Collection<T> list, Function<T, K> getV) {
        return list.stream().collect(Collectors.toMap(e -> e, getV));
    }

    /**
     * 列表转Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K> Map<K, T> toMapFK(Collection<T> list, Predicate<? super T> filter, Function<T, K> getK) {
        return list.stream().filter(filter).collect(Collectors.toMap(getK, e -> e));
    }

    /**
     * 列表转Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K, U> Map<K, U> toMapKV(Collection<T> list, Function<T, K> getK, Function<? super T, ? extends U> getV) {
        return list.stream().collect(Collectors.toMap(getK, getV));
    }

    /**
     * 列表转Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K, U> Map<K, U> toMapFKV(Collection<T> list, Predicate<? super T> filter, Function<T, K> getK, Function<? super T, ? extends U> getV) {
        return list.stream().filter(filter).collect(Collectors.toMap(getK, getV));
    }

    /**
     * 列表转二维Map
     *
     * @param list 列表
     * @param getK 第一维 key
     * @param getV 第一维 value（列表）
     * @param getA 第二维 key
     * @param <T>  T
     * @param <K>  K
     * @param <V>  V
     * @param <A>  A
     * @return 二维Map
     */
    public static <T, K, V, A> Map<K, Map<A, V>> toMapAndThen(Collection<T> list, Function<T, K> getK, Function<T, Collection<V>> getV, Function<V, A> getA) {
        return list.stream().collect(Collectors.toMap(getK, e -> getV.apply(e).stream().collect(Collectors.toMap(getA, v -> v))));
    }

    /**
     * 列表转二维Map
     *
     * @param list 列表
     * @param getK 第一维 key
     * @param getV 第一维 value（列表）
     * @param getA 第二维 key
     * @param <T>  T
     * @param <K>  K
     * @param <V>  V
     * @param <A>  A
     * @return 二维Map
     */
    public static <T, K, V, A, B> Map<K, Map<A, B>> toMapAndThen(Collection<T> list, Function<T, K> getK, Function<T, Collection<V>> getV, Function<V, A> getA, Function<V, B> getB) {
        return list.stream().collect(Collectors.toMap(getK, e -> getV.apply(e).stream().collect(Collectors.toMap(getA, getB))));
    }

    /**
     * 列表转有序Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K> Map<K, T> toOrderlyMapK(Collection<T> list, Function<T, K> getK) {
        return list.stream().collect(StreamUtil.orderlyToMap(getK, e -> e));
    }

    /**
     * 列表转有序Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K> Map<K, T> toOrderlyMapCK(Collection<T> list, Comparator<T> comparator, Function<T, K> getK) {
        return list.stream().sorted(comparator).collect(StreamUtil.orderlyToMap(getK, e -> e));
    }

    /**
     * 列表转有序Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K> Map<K, T> toOrderlyMapFK(Collection<T> list, Function<T, K> getK, Predicate<T> filter) {
        return list.stream().filter(filter).collect(StreamUtil.orderlyToMap(getK, e -> e));
    }

    /**
     * 列表转有序Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K, U> Map<K, U> toOrderlyMapKV(Collection<T> list, Function<T, K> getK, Function<? super T, ? extends U> getV) {
        return list.stream().collect(StreamUtil.orderlyToMap(getK, getV));
    }

    /**
     * 列表转有序Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K, U> Map<K, U> toOrderlyMapCKV(Collection<T> list, Comparator<T> comparator, Function<T, K> getK, Function<T, U> getV) {
        return list.stream().sorted(comparator).collect(StreamUtil.orderlyToMap(getK, getV));
    }

    /**
     * 列表转有序Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K, V> Map<K, V> toOrderlyMapFKV(Collection<T> list, Predicate<T> filter, Function<T, K> getK, Function<T, V> getV) {
        return list.stream().filter(filter).collect(StreamUtil.orderlyToMap(getK, getV));
    }

    /**
     * 转换Map
     *
     * @param map  map
     * @param getK key方法
     * @param <K>  K
     * @param <U>  U
     * @param <A>  A
     * @return Map
     */
    public static <K, U, A> Map<A, U> transMapK(Map<K, U> map, Function<K, A> getK) {
        return map.entrySet().stream().collect(Collectors.toMap(e -> getK.apply(e.getKey()), Map.Entry::getValue));
    }

    /**
     * 转换Map
     *
     * @param map    map
     * @param getK   key方法
     * @param filter 过滤
     * @param <K>    K
     * @param <U>    U
     * @param <A>    A
     * @return Map
     */
    public static <K, U, A> Map<A, U> transMapFK(Map<K, U> map, BiPredicate<K, U> filter, Function<K, A> getK) {
        return StreamUtil.toMapFKV(map.entrySet(), entry -> filter.test(entry.getKey(), entry.getValue()), e -> getK.apply(e.getKey()), Map.Entry::getValue);
    }

    /**
     * 转换Map
     *
     * @param map  map
     * @param getK key方法
     * @param getV VALUE方法
     * @param <K>  K
     * @param <U>  U
     * @param <A>  A
     * @param <D>  D
     * @return Map
     */
    public static <K, U, A, D> Map<A, D> transMapKV(Map<K, U> map, Function<K, A> getK, Function<U, D> getV) {
        return map.entrySet().stream().collect(Collectors.toMap(e -> getK.apply(e.getKey()), e -> getV.apply(e.getValue())));
    }

    /**
     * 转换Map
     *
     * @param map  map
     * @param getK key方法
     * @param getV VALUE方法
     * @param <K>  K
     * @param <U>  U
     * @param <A>  A
     * @param <D>  D
     * @return Map
     */
    public static <K, U, A, D> Map<A, D> transMapKV(Map<K, U> map, Function<K, A> getK, BiFunction<K, U, D> getV) {
        return map.entrySet().stream().collect(Collectors.toMap(e -> getK.apply(e.getKey()), e -> getV.apply(e.getKey(), e.getValue())));
    }

    /**
     * 转换Map
     *
     * @param map  map
     * @param getV VALUE方法
     * @param <K>  K
     * @param <U>  U
     * @param <D>  D
     * @return Map
     */
    public static <K, U, D> Map<K, D> transMapV(Map<K, U> map, Function<U, D> getV) {
        return map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> getV.apply(e.getValue())));
    }

    /**
     * 转换Map
     *
     * @param map  map
     * @param getV VALUE方法
     * @param <K>  K
     * @param <U>  U
     * @param <D>  D
     * @return Map
     */
    public static <K, U, D> Map<K, D> transMapV_Expand(Map<K, U> map, BiFunction<K, U, D> getV) {
        return map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> getV.apply(e.getKey(), e.getValue())));
    }

    /**
     * 拼接 value为List的Map 的values
     *
     * @param map map
     * @param <K> k
     * @param <U> u
     * @return Collection
     */
    public static <K, U, L extends Collection<U>> L concatMapColValues(Map<K, L> map) {
        L l = null;
        for (L value : map.values()) {
            if (Objects.isNull(l)) {
                l = value;
            } else {
                l.addAll(value);
            }
        }
        return l;
    }

    /**
     * 拼接values
     *
     * @param map map
     * @param <K> k
     * @param <A> a
     * @param <B> b
     * @return Map
     */
    public static <K, A, B> Map<A, B> concatMapValues(Map<K, Map<A, B>> map) {
        Map<A, B> result = new LinkedHashMap<>();
        map.values().forEach(result::putAll);
        return result;
    }

    /**
     * 拼接map key和values 为新的set
     *
     * @param map map
     * @param <T> t
     * @return Collection
     */
    public static <T> Set<T> concatMapKeyValues(Map<T, T> map) {
        return CollectionUtil.unionDistinct(map.keySet(), map.values());
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K> Map<K, List<T>> groupK(Collection<T> list, Function<T, K> getK) {
        return list.stream().collect(Collectors.groupingBy(getK));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, V> Map<K, List<V>> groupAndThen(Collection<T> list, Function<T, K> getK, Function<List<T>, List<V>> getV) {
        return list.stream().collect(Collectors.groupingBy(getK, Collectors.collectingAndThen(Collectors.toList(), getV)));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, V> Map<K, Set<V>> groupAndThenSet(Collection<T> list, Function<T, K> getK, Function<Set<T>, Set<V>> getV) {
        return list.stream().collect(Collectors.groupingBy(getK, Collectors.collectingAndThen(Collectors.toSet(), getV)));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, V> Map<K, List<V>> groupFAndThen(Collection<T> list, Predicate<T> filter, Function<T, K> getK, Function<List<T>, List<V>> getV) {
        return list.stream().filter(filter).collect(Collectors.groupingBy(getK, Collectors.collectingAndThen(Collectors.toList(), getV)));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, V> Map<K, List<V>> groupAndThenTrans(Collection<T> list, Function<T, K> getK, Function<T, V> getV) {
        return StreamUtil.groupAndThen(list, getK, l -> StreamUtil.transListT(l, getV));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, V> Map<K, Set<V>> groupAndThenTransSet(Collection<T> list, Function<T, K> getK, Function<T, V> getV) {
        return StreamUtil.groupAndThenSet(list, getK, set -> StreamUtil.transSetT(set, getV));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, V> Map<K, List<V>> groupFAndThenTrans(Collection<T> list, Predicate<T> filter, Function<T, K> getK, Function<T, V> getV) {
        return list.stream().filter(filter).collect(Collectors.groupingBy(getK, Collectors.collectingAndThen(Collectors.toList(),
                child -> child.stream().map(getV).collect(Collectors.toList()))));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, MK> Map<K, Map<MK, T>> groupAndThenTransMapK(Collection<T> list, Function<T, K> getK, Function<T, MK> getMK) {
        return StreamUtil.groupAndThenListToMap(list, getK, l -> StreamUtil.toMapK(l, getMK));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, MK> Map<K, Map<MK, T>> groupFAndThenTransMapK(Collection<T> list, Predicate<T> filter, Function<T, K> getK, Function<T, MK> getMK) {
        return list.stream().filter(filter).collect(Collectors.groupingBy(getK,
                Collectors.collectingAndThen(Collectors.toList(), l -> StreamUtil.toMapK(l, getMK))));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, A> Map<K, Map<A, List<T>>> groupAndThenGroup(Collection<T> list, Function<T, K> getK, Function<T, A> getA) {
        return StreamUtil.groupAndThenListToMap(list, getK, l -> StreamUtil.groupK(l, getA));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, A> Map<K, Map<A, List<T>>> groupFAndThenGroup(Collection<T> list, Predicate<T> filter, Function<T, K> getK, Function<T, A> getA) {
        return StreamUtil.groupFAndThenListToMap(list, filter, getK, l -> StreamUtil.groupK(l, getA));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, A, B> Map<K, Map<A, List<B>>> groupAndThenGroupTrans(Collection<T> list, Function<T, K> getK, Function<T, A> getA, Function<T, B> getB) {
        return StreamUtil.groupAndThenListToMap(list, getK, l -> StreamUtil.groupAndThenTrans(l, getA, getB));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, A, B> Map<K, Map<A, Set<B>>> groupAndThenGroupTransSet(Collection<T> list, Function<T, K> getK, Function<T, A> getA, Function<T, B> getB) {
        return StreamUtil.groupAndThenListToMap(list, getK, l -> StreamUtil.groupAndThenTransSet(l, getA, getB));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, A, B> Map<K, Map<A, B>> groupAndThenListToMap(Collection<T> list, Function<T, K> getK, Function<List<T>, Map<A, B>> toMap) {
        return list.stream().collect(Collectors.groupingBy(getK, Collectors.collectingAndThen(Collectors.toList(), toMap)));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, A, B> Map<K, Map<A, B>> groupFAndThenListToMap(Collection<T> list, Predicate<T> filter, Function<T, K> getK, Function<List<T>, Map<A, B>> toMap) {
        return list.stream().filter(filter).collect(Collectors.groupingBy(getK, Collectors.collectingAndThen(Collectors.toList(), toMap)));
    }

    /**
     * 先排序然后分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, U extends Comparable<? super U>> Map<K, List<T>> sortAndGroup(Collection<T> list, Function<T, U> sorted, Function<T, K> getK) {
        return list.stream().sorted(Comparator.comparing(sorted)).collect(StreamUtil.orderlyGroupBy(getK, Collectors.toList()));
    }

    /**
     * 任意符合
     *
     * @param list      list
     * @param predicate 判断方法
     * @param <T>       T
     * @return Map
     */
    public static <T> boolean anyMatch(Collection<T> list, Predicate<? super T> predicate) {
        return list.stream().anyMatch(predicate);
    }

    /**
     * 从map中获取值
     *
     * @param map  map
     * @param keys keys
     * @param <K>  K
     * @param <V>  V
     * @return List
     */
    public static <K, V> List<V> findMapValue(Map<K, V> map, List<K> keys) {
        return keys.stream().filter(map::containsKey).map(map::get).collect(Collectors.toList());
    }
}
